/**
 * Description: SLE多节点连接管理链表，用于存储SLE客户端所连接的节点信息. \n
 *              使用单向链表存储节点信息，链表头指针为 sle_node_list_t *g_sle_NodeList_head.
 *
 * History: \n
 * 2025-05-14, Create file. \n
 */

#include "sle_node_list.h"

#include "osal_addr.h"
#include "soc_osal.h"
#include "securec.h"

#define CODE_LOG "[SLE Node List]"

sle_node_list_t *g_sle_NodeList_head = NULL; // 链表头指针
uint16_t g_sle_NodeList_count = 0;           // 链表节点数量

/**
 * @brief  初始化SLE节点链表.
 * @param  无
 * @return errcode_t 成功返回 ERRCODE_SUCC ，失败返回其他错误码
 */
errcode_t SLE_NodeList_Init(void)
{
    g_sle_NodeList_head = osal_kmalloc(sizeof(sle_node_list_t), 0); // 分配内存
    if (g_sle_NodeList_head == NULL)
    {
        osal_printk("%s SLE_NodeList_Init malloc failed\n", CODE_LOG);

        return ERRCODE_FAIL;
    }

    // 初始化链表信息
    g_sle_NodeList_head->next = NULL;
    g_sle_NodeList_count = 0;

    return ERRCODE_SUCC;
}

/**
 * @brief  销毁SLE节点链表.
 * @param  无
 * @return errcode_t 成功返回 ERRCODE_SUCC ，失败返回其他错误码
 */
errcode_t SLE_NodeList_Destroy(void)
{
    sle_node_list_t *current = g_sle_NodeList_head;
    sle_node_list_t *prev = NULL;

    while (current != NULL)
    {
        prev = current;
        current = current->next;
        osal_kfree(prev); // 释放上一节点内存
    }

    // 链表头指针和节点数量置空
    g_sle_NodeList_count = 0;
    g_sle_NodeList_head = NULL;

    return ERRCODE_SUCC;
}

/**
 * @brief  添加SLE节点到链表.
 * @param  [in]    conn_id 节点连接ID
 * @param  [in]    device_type 节点类型
 * @param  [in]    device_type_len 节点类型长度
 * @param  [in]    addr 节点地址
 * @return errcode_t 成功返回 ERRCODE_SUCC ，失败返回其他错误码
 * @note   1. 链表需要调用 SLE_NodeList_Init() 函数初始化，否则添加失败
 *         2. device_type 和 addr 不能为空，且 device_type 数据长度不能超过 SLE_ADV_VALUE_MAX_LENGTH
 *         3. 链表节点数量 g_sle_NodeList_count 不能超过 SLE_NODE_LIST_MAX_COUNT
 */
errcode_t SLE_NodeList_Add(uint16_t conn_id, char *device_type, uint16_t device_type_len, const sle_addr_t *addr)
{
    // 检查链表是否初始化
    if (g_sle_NodeList_head == NULL)
    {
        osal_printk("%s SLE_NodeList_Add node list is null\n", CODE_LOG);
        return ERRCODE_FAIL;
    }

    // 检查参数是否合法
    if (device_type == NULL || addr == NULL)
    {
        osal_printk("%s SLE_NodeList_Add device_type or addr is null\n", CODE_LOG);
        return ERRCODE_INVALID_PARAM;
    }

    // 创建新节点
    sle_node_list_t *new_node = osal_kmalloc(sizeof(sle_node_list_t), 0); // 分配内存
    if (new_node == NULL)
    {
        osal_printk("%s SLE_NodeList_Add malloc failed\n", CODE_LOG);
        return ERRCODE_FAIL;
    }

    // 初始化节点信息
    new_node->device_info.sle_conn_id = conn_id;
    (void)memcpy_s(new_node->device_info.sle_device_type, SLE_ADV_VALUE_MAX_LENGTH, device_type, device_type_len);
    (void)memcpy_s(&new_node->device_info.sle_device_addr, sizeof(sle_addr_t), addr, sizeof(sle_addr_t));
    new_node->next = NULL;

    // 将新节点添加到链表尾部
    sle_node_list_t *current = g_sle_NodeList_head;
    while (current->next != NULL)
    {
        current = current->next;
    }
    current->next = new_node;

    g_sle_NodeList_count++; // 更新链表节点数量
    osal_printk("%s SLE_NodeList_Add node list count: %d\n", CODE_LOG, g_sle_NodeList_count);

    return ERRCODE_SUCC;
}

/**
 * @brief 根据节点的addr，从节点列表中删除指定节点
 * @param  [in]    addr 需要删除节点的地址
 * @return errcode_t 成功返回 ERRCODE_SUCC ，失败返回其他错误码
 * @note   1. 链表需要调用 SLE_NodeList_Init() 函数初始化，否则添加失败
 *         2. addr 不能为空
 * */
errcode_t SLE_NodeList_Remove(const sle_addr_t *addr)
{
    // 检查链表是否初始化
    if (g_sle_NodeList_head == NULL)
    {
        osal_printk("%s SLE_NodeList_Delete node list is null\n", CODE_LOG);
        return ERRCODE_FAIL;
    }

    // 检查参数
    if (addr == NULL)
    {
        osal_printk("%s SLE_NodeList_Delete addr is null\n", CODE_LOG);
        return ERRCODE_INVALID_PARAM;
    }

    // 遍历链表查找要删除的节点
    sle_node_list_t *current = g_sle_NodeList_head->next; // 从头节点的下一个节点开始遍历
    sle_node_list_t *prev = g_sle_NodeList_head;
    while (current != NULL)
    {
        if (memcmp(&current->device_info.sle_device_addr, addr, sizeof(sle_addr_t)) == 0)
        {
            prev->next = current->next; // 删除当前节点
            osal_kfree(current);        // 释放当前节点内存
            g_sle_NodeList_count--;     // 更新链表节点数量

            break; // 找到并删除节点后退出循环
        }
        prev = current;
        current = current->next; // 继续遍历下一个节点
    }

    // 如果没有找到要删除的节点，则返回错误
    if (current == NULL)
    {
        osal_printk("%s SLE_NodeList_Delete node not found\n", CODE_LOG);
        return ERRCODE_FAIL;
    }

    osal_printk("%s SLE_NodeList_Delete node list count: %d\n", CODE_LOG, g_sle_NodeList_count);
    return ERRCODE_SUCC;
}

/**
 * @brief 根据节点的设备类型，获取节点地址
 * @param device_type 设备类型
 * @param device_type_len 设备类型长度
 * @return sle_node_list_t 指向查找到节点的地址，NULL表示未找到
 * @note   1. 链表需要调用 SLE_NodeList_Init() 函数初始化，否则添加失败
 *         2. device_type 不能为空，且 device_type 数据长度不能超过 SLE_ADV_VALUE_MAX_LENGTH
 * */
sle_node_list_t *SLE_NodeList_Find(char *device_type, uint16_t device_type_len)
{
    // 检查链表是否初始化
    if (g_sle_NodeList_head == NULL)
    {
        osal_printk("%s SLE_NodeList_Find node list is null\n", CODE_LOG);
        return NULL;
    }

    // 检查参数
    if (device_type == NULL || device_type_len > SLE_ADV_VALUE_MAX_LENGTH)
    {
        osal_printk("%s SLE_NodeList_Find addr is null\n", CODE_LOG);
        return NULL;
    }

    // 遍历链表查找节点
    sle_node_list_t *current = g_sle_NodeList_head->next; // 从头节点的下一个节点开始遍历
    while (current != NULL)
    {
        if (memcmp(&current->device_info.sle_device_type, device_type, device_type_len) == 0)
        {
            break; // 找到节点后退出循环
        }
        current = current->next; // 继续遍历下一个节点
    }

    return current;
}

/**
 * @brief  显示链表节点信息
 * @param  无
 * @return errcode_t 成功返回 ERRCODE_SUCC ，失败返回其他错误码
 * @note   1. 链表需要调用 SLE_NodeList_Init() 函数初始化，否则添加失败
 */
errcode_t SLE_NodeList_Print(void)
{
    if (g_sle_NodeList_head == NULL)
    {
        osal_printk("%s SLE_NodeList_Print node list is null\n", CODE_LOG);
        return ERRCODE_FAIL;
    }
    osal_printk("%s SLE_NodeList_Print node list count: %d\n", CODE_LOG, g_sle_NodeList_count);

    // 从头节点的下一个节点开始遍历
    sle_node_list_t *current = g_sle_NodeList_head->next; 
    osal_printk("%s SLE_NodeList_Print node list info: Head", CODE_LOG);
    while (current != NULL)
    {
        osal_printk(" -> %s", current->device_info.sle_device_type);
        current = current->next; // 继续遍历下一个节点
    }
    osal_printk("\n");
    
    return ERRCODE_SUCC;
}